<?php

declare(strict_types=1);

namespace Zlf\AppValidate\Rule;

/**
 * 元素是否在数组中验证
 * 用于验证输入值是否存在于预定义的枚举数组中。
 * 支持严格模式，可同时检查值和类型。
 */
class InValidate extends RuleAbstract
{
    /**
     * 枚举数据源
     * 存储允许的值列表。
     * @var array
     */
    protected $_enums = [];

    /**
     * 错误提示
     * 当验证失败时返回的错误信息模板。
     * @var string
     */
    protected $_error = '{label}选择错误';

    /**
     * 是否还要检查类型
     * 如果设置为 true，则在验证时会同时检查值和类型。
     * @var bool
     */
    protected $_strict = false;

    /**
     * 设置枚举数据
     * 定义允许的值列表。
     * @param array $enums 枚举值数组
     * @return $this
     */
    public function setEnums(array $enums): InValidate
    {
        $this->_enums = $enums;
        return $this;
    }

    /**
     * 设置是否启用严格模式
     * 在严格模式下，验证时会同时检查值和类型。
     * @param bool $strict 是否启用严格模式
     * @return $this
     */
    public function setStrict(bool $strict): InValidate
    {
        $this->_strict = $strict;
        return $this;
    }

    /**
     * 验证输入值是否在枚举数组中
     * 如果输入值为空且 `_noSkipping` 为 true，则直接返回 true。
     * 否则，使用 `in_array` 检查值是否存在于枚举数组中。
     * @param mixed $value 输入值
     * @param string $label 验证名（用于错误信息中）
     * @return bool 验证结果
     */
    public function validate($value, string $label = ''): bool
    {
        // 确保输入值是字符串或数字
        if (is_string($value) || is_numeric($value)) {
            // 如果值为空且 `_noSkipping` 为 true，则直接返回 true
            if (empty($value) && $this->_noSkipping === true) {
                $this->_value = $value;
                return true;
            }
            // 使用 `in_array` 检查值是否存在于枚举数组中
            if (in_array($value, $this->_enums, $this->_strict)) {
                $this->_value = $value;
                return true;
            }
        }
        // 如果验证失败，添加错误信息并返回 false
        return $this->addError($this->_error, $label);
    }
}
